﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Experimental Dilate
    /// </summary>
    public class ExperimentalDilate : ExperimentalMorphology
    {
        // Element array to used to dilate.
        byte[,] sElement = new byte[5, 5] { 
        {0,0,1,0,0},
        {0,1,1,1,0},
        {1,1,1,1,1},
        {0,1,1,1,0},
        {0,0,1,0,0}
    };

        /// <summary>
        /// Initializes a new instance of the <see cref="ExperimentalDilate"/> class.
        /// </summary>
        public ExperimentalDilate()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ExperimentalDilate"/> class.
        /// </summary>
        /// <param name="_ExperimentalDilate">The _experimental closing.</param>
        internal ExperimentalDilate(ExperimentalDilate _ExperimentalDilate)
        {
        }

        /// <summary>
        /// Executes the specified bitmap.
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            // Element array size.
            int size = 5;
            byte max, clrValue;
            int radius = size / 2;
            int ir, jr;

            unsafe
            {
                UnsafeBitmap SrcDataBitmap = (UnsafeBitmap)_bitmap.Clone();
                BitmapData SrcData = SrcDataBitmap.BitmapData;
                BitmapData DestData = _bitmap.BitmapData;
                int nBytesPerPixel = SrcDataBitmap.BytesPerPixelCount;
                // Loop for Columns.
                for (int colm = radius; colm < DestData.Height - radius; colm++)
                {
                    // Initialise pointers to at row start.
                    byte* ptr = (byte*)SrcData.Scan0 + (colm * SrcData.Stride);
                    byte* dstPtr = (byte*)DestData.Scan0 + (colm * SrcData.Stride);

                    // Loop for Row item.
                    for (int row = radius; row < DestData.Width - radius; row++)
                    {
                        max = 0;
                        clrValue = 0;

                        // Loops for element array.
                        for (int eleColm = 0; eleColm < 5; eleColm++)
                        {
                            ir = eleColm - radius;
                            byte* tempPtr = (byte*)SrcData.Scan0 +
                                ((colm + ir) * SrcData.Stride);

                            for (int eleRow = 0; eleRow < 5; eleRow++)
                            {
                                jr = eleRow - radius;

                                // Get neightbour element color value.
                                clrValue = (byte)((tempPtr[row * 3+ jr] +
                                    tempPtr[row * 3 + jr + 1] + tempPtr[row * 3+ jr + 2]) / 3);

                                if (max < clrValue)
                                {
                                    if (sElement[eleColm, eleRow] != 0)
                                        max = clrValue;
                                }
                            }
                        }

                        dstPtr[0] = dstPtr[1] = dstPtr[2] = max;

                        ptr += 3;
                        dstPtr += 3;
                    }
                }
                SrcDataBitmap.UnlockImage();
            }

            // return dilated bitmap.
            return _bitmap;
        }
        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new ExperimentalDilate();
        }
    }
}
